#include "RingFIFO.h"

/**
 * @brief 环形FIFO缓冲区初始化函数
 *
 * @param fifo
 * @param buffer
 * @param size
 * @return uint16_t
 */
uint16_t RingFIFO_Init(RingFIFO_t *fifo, uint8_t *buffer, uint16_t size)
{
    if (fifo == NULL || buffer == NULL || size == 0)
    {
        return 0; // 初始化失败
    }

    fifo->buffer = buffer;
    fifo->size = size;
    fifo->head = 0;
    fifo->tail = 0;

    return size; // 返回缓冲区大小
}

/**
 * @brief 向环形FIFO缓冲区写入数据
 *
 * @param fifo
 * @param data
 * @param length
 * @return uint16_t 实际写入的字节数
 */
uint16_t RingFIFO_Write(RingFIFO_t *fifo, const uint8_t *data, uint16_t length)
{
    if (fifo == NULL || data == NULL || length == 0)
    {
        return 0; // 写入失败
    }

    uint16_t written = 0;
    for (uint16_t i = 0; i < length; i++)
    {
        if ((fifo->head + 1) % fifo->size == fifo->tail) // 缓冲区满
        {
            break; // 停止写入
        }
        fifo->buffer[fifo->head] = data[i];
        fifo->head = (fifo->head + 1) % fifo->size;
        written++;
    }

    return written; // 返回实际写入的字节数
}

/**
 * @brief 从环形FIFO缓冲区读取数据
 *
 * @param fifo
 * @param data
 * @param length
 * @return uint16_t 实际读取的字节数
 *
 * @note 如果读取长度超过可用数据长度，则只读取可用数据长度
 * @note 读取完毕后，尾索引会更新，不必手动更新
 */
uint16_t RingFIFO_Read(RingFIFO_t *fifo, uint8_t *data, uint16_t length)
{
    if (fifo == NULL || data == NULL || length == 0)
    {
        return 0; // 读取失败
    }

    uint16_t read = 0;
    for (uint16_t i = 0; i < length; i++)
    {
        if (fifo->head == fifo->tail) // 缓冲区空
        {
            break; // 停止读取
        }
        data[i] = fifo->buffer[fifo->tail];
        fifo->tail = (fifo->tail + 1) % fifo->size;
        read++;
    }

    return read; // 返回实际读取的字节数
}

/**
 * @brief 获取环形FIFO缓冲区的当前大小
 *
 * @param fifo
 * @return uint16_t 当前大小
 */
uint16_t RingFIFO_Size(RingFIFO_t *fifo)
{
    if (fifo == NULL)
    {
        return 0; // 获取大小失败
    }

    if (fifo->head >= fifo->tail)
    {
        return fifo->head - fifo->tail; // 正常情况
    }
    else
    {
        return fifo->size - (fifo->tail - fifo->head); // 环形情况
    }
}

/**
 * @brief 获取当前索引下的值
 *
 * @param fifo 指向环形FIFO结构体的指针
 * @param index 索引位置
 *
 * @return uint8_t 返回指定索引位置的值，如果索引无效则返回0
 */
uint8_t RingFIFO_GetValueAtIndex(RingFIFO_t *fifo, uint16_t index)
{
    if (fifo == NULL || index >= RingFIFO_Size(fifo))
    {
        return 0; // 获取失败
    }

    uint16_t actualIndex = (fifo->tail + index) % fifo->size;
    return fifo->buffer[actualIndex]; // 返回指定索引的值
}

/**
 * @brief 由其它方法写入数据（如DMA）后，更新索引以便后续读取
 *
 * @param fifo 指向环形FIFO结构体的指针
 * @param length 新写入数据的长度
 * @return uint16_t 返回更新后的头索引
 */
uint16_t RingFIFO_UpdateHeadIndex(RingFIFO_t *fifo, uint16_t length)
{
    if (fifo == NULL || length == 0)
    {
        return fifo->head; // 更新失败，返回当前头索引
    }

    fifo->head = (fifo->head + length) % fifo->size; // 更新头索引
    return fifo->head; // 返回更新后的头索引
}

/**
 * @brief 直接设置环形FIFO缓冲区的头索引
 *
 * @param fifo 指向环形FIFO结构体的指针
 * @param head 新的头索引
 * @return uint16_t 返回设置后的头索引
 */
uint16_t RingFIFO_SetHeadIndex(RingFIFO_t *fifo, uint16_t head)
{
    if (fifo == NULL || head >= fifo->size)
    {
        return fifo->head; // 设置失败，返回当前头索引
    }

    fifo->head = head; // 设置新的头索引
    return fifo->head; // 返回设置后的头索引
}

/**
 * @brief 清空环形FIFO缓冲区（将尾索引重置为头索引）
 *
 * @param fifo 指向环形FIFO结构体的指针
 * @return uint16_t 返回清空后的头索引
 */
uint16_t RingFIFO_Clear(RingFIFO_t *fifo)
{
    if (fifo == NULL)
    {
        return 0; // 清空失败
    }

    fifo->tail = fifo->head; // 将尾索引重置为头索引
    return fifo->head; // 返回清空后的头索引
}

/**
 * @brief 设置环形FIFO缓冲区为零（重置头尾索引并清空缓冲区）
 *
 * @param fifo 指向环形FIFO结构体的指针
 */
void RingFIFO_SetZero(RingFIFO_t *fifo)
{
    if (fifo == NULL)
    {
        return; // 设置失败
    }

    fifo->head = 0; // 重置头索引
    fifo->tail = 0; // 重置尾索引
    memset(fifo->buffer, 0, fifo->size); // 清空缓冲区
    // 注意：如果需要保留缓冲区内容，可以不清空
}

